package imp

import (
	sqlc "bgs/db/sqlc"
	brandSpokesmanGrpc "bgs/grpc/gen/service/brand_spokesman"
	"bgs/grpc/gen/shared/message"
	"bgs/util"
	"context"
	"fmt"
)

/****************************************************************************************/
/*                               brand_spokesman entity of helper                       */
/****************************************************************************************/

func transformBrandSpokesmanEntityToPb(o sqlc.Spokesman) *brandSpokesmanGrpc.BrandSpokesmanEntity {
	return &brandSpokesmanGrpc.BrandSpokesmanEntity{
		Id:                   o.ID,
		UserId:               o.UserID,
		BrandId:              o.BrandID,
		AliasName:            o.AliasName,
		Became:               sqlc.GoTimeToPBTimestamp(o.Became),
		Remark:               o.Remark.String,
		EndorseActivityCount: o.EndorseActivityCount,
		SaleAmount:           o.SaleAmount,
	}
}

func mapBrandSpokesmanEntityToPb(list []sqlc.Spokesman, f func(sqlc.Spokesman) *brandSpokesmanGrpc.BrandSpokesmanEntity) []*brandSpokesmanGrpc.BrandSpokesmanEntity {
	r := make([]*brandSpokesmanGrpc.BrandSpokesmanEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                               brand_spokesman entity of cmd                          */
/****************************************************************************************/

// BecomeBrandSpokesman 成为品牌代言人(deprecated)
func (s *BrandAPIService) BecomeBrandSpokesman(ctx context.Context, req *brandSpokesmanGrpc.BecomeBrandSpokesmanRequest) (res *brandSpokesmanGrpc.BecomeBrandSpokesmanResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_spokesmanImp->BecomeBrandSpokesman:%v", req)
	res = &brandSpokesmanGrpc.BecomeBrandSpokesmanResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var brandSpokesman sqlc.Spokesman

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {
		brandID := req.BrandId
		endorseObjectKey := fmt.Sprintf("%d-0", brandID)
		brandSpokesman, err = q.UpsertSpokesman(ctx, sqlc.UpsertSpokesmanParams{
			UserID:           req.UserId,
			BrandID:          brandID,
			EndorseObjectKey: endorseObjectKey,
			AliasName:        req.AliasName,
			Became:           sqlc.PBTimestampToGoTime(req.Became),
		})
		if err != nil {
			return err
		}
		slog.Info("2 insert brand_spokesman ok")

		user, err := q.GetUser(ctx, brandSpokesman.UserID)
		if err != nil {
			return err
		}
		slog.Info("2 获取user ok")
		userRoles := user.Roles
		if !util.StringContains(userRoles, string(sqlc.EmUserRoleBrandSpokesman)) {
			newUserRoles := append(userRoles, string(sqlc.EmUserRoleBrandSpokesman))
			user, err = q.UpdateUserRoles(ctx, sqlc.UpdateUserRolesParams{
				ID:    brandSpokesman.UserID,
				Roles: newUserRoles,
			})
			if err != nil {
				return err
			}
			slog.Info("3 更新用户roles ok")
		}

		err = s.brandService.UpdateBrandStatSpokesmanCountSinceUpsertBrandSpokesman(ctx, q, brandID)
		if err != nil {
			return
		}
		slog.Infof("4 更新品牌统计的spokesman_count ok")

		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.BrandSpokesman = transformBrandSpokesmanEntityToPb(brandSpokesman)
	return
}

// UpdateBrandSpokesman 更新品牌代言人
func (s *BrandAPIService) UpdateBrandSpokesman(ctx context.Context, req *brandSpokesmanGrpc.UpdateBrandSpokesmanRequest) (res *brandSpokesmanGrpc.UpdateBrandSpokesmanResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_spokesmanImp->UpdateBrandSpokesman:%v", req)
	res = &brandSpokesmanGrpc.UpdateBrandSpokesmanResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	BrandSpokesman, err := s.dao.Q.UpdateSpokesman(ctx, sqlc.UpdateSpokesmanParams{
		ID:        req.Id,
		AliasName: req.AliasName,
		Remark:    sqlc.NSFromString(req.Remark),
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.BrandSpokesman = transformBrandSpokesmanEntityToPb(BrandSpokesman)
	return
}

// CancelBrandSpokesman 取消品牌代言人(deprecated)
func (s *BrandAPIService) CancelBrandSpokesman(ctx context.Context, req *brandSpokesmanGrpc.CancelBrandSpokesmanRequest) (res *brandSpokesmanGrpc.CancelBrandSpokesmanResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_spokesmanImp->CancelBrandSpokesman:%v", req)
	res = &brandSpokesmanGrpc.CancelBrandSpokesmanResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var BrandSpokesman sqlc.Spokesman

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		BrandSpokesman, err = q.DisableSpokesman(ctx, req.Id)
		if err != nil {
			return err
		}
		slog.Info("1 disable brand_spokesman ok")

		total, err := q.CountNormalBrandSpokesmansByUserID(ctx, BrandSpokesman.UserID)
		if err != nil {
			return err
		}
		slog.Infof("2 CountBrandSpokesmansByUserID=>%d", total)

		if total == 0 {
			user, err := q.GetUser(ctx, BrandSpokesman.UserID)
			if err != nil {
				return err
			}
			slog.Info("3 获取user ok")
			userRoles := user.Roles

			newUserRoles := util.StringFilter(userRoles, func(s string) bool {
				return s != string(sqlc.EmUserRoleBrandSpokesman)
			})
			user, err = q.UpdateUserRoles(ctx, sqlc.UpdateUserRolesParams{
				ID:    BrandSpokesman.UserID,
				Roles: newUserRoles,
			})
			if err != nil {
				return err
			}
			slog.Info("4 更新用户roles ok")
		}

		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.BrandSpokesman = transformBrandSpokesmanEntityToPb(BrandSpokesman)
	return
}

/****************************************************************************************/
/*                            brand_spokesman entity of query                           */
/****************************************************************************************/

// GetBrandSpokesman 获取单个品牌代言人
func (s *BrandAPIService) GetBrandSpokesman(ctx context.Context, req *brandSpokesmanGrpc.GetBrandSpokesmanRequest) (res *brandSpokesmanGrpc.GetBrandSpokesmanResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_spokesmanImp->GetBrandSpokesman:%v", req)
	res = &brandSpokesmanGrpc.GetBrandSpokesmanResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	brandSpokesman, err := s.dao.Q.GetSpokesman(ctx, req.Id)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.BrandSpokesman = transformBrandSpokesmanEntityToPb(brandSpokesman)
	return
}

// ListNormalBrandSpokesmansByBrandID  获取正常的品牌代言人列表
func (s *BrandAPIService) ListNormalBrandSpokesmansByBrandID(ctx context.Context, req *brandSpokesmanGrpc.ListNormalBrandSpokesmansByBrandIDRequest) (res *brandSpokesmanGrpc.ListNormalBrandSpokesmansByBrandIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_spokesmanImp->ListNormalBrandSpokesmansByBrandID:%v", req)

	res = &brandSpokesmanGrpc.ListNormalBrandSpokesmansByBrandIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	total, err := s.dao.Q.CountNormalBrandSpokesmansByBrandID(ctx, req.BrandId)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}
	brandSpokesmans, err := s.dao.Q.ListNormalBrandSpokesmansByBrandID(ctx, sqlc.ListNormalBrandSpokesmansByBrandIDParams{
		Limit:   req.Limit,
		Offset:  req.Offset,
		BrandID: req.BrandId,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.BrandSpokesmans = mapBrandSpokesmanEntityToPb(brandSpokesmans, transformBrandSpokesmanEntityToPb)
	return
}

/****************************************************************************************/
/*                            brand_spokesmanJoins entity of helper                     */
/****************************************************************************************/

func transformBrandSpokesmanWithBrandEntityToPb(row sqlc.ListNormalBrandSpokesmanWithBrandsByUserIDRow) *brandSpokesmanGrpc.BrandSpokesmanWithBrandEntity {
	return &brandSpokesmanGrpc.BrandSpokesmanWithBrandEntity{
		// brand_admin
		Id:        row.ID,
		UserId:    row.UserID,
		BrandId:   row.BrandID,
		AliasName: row.AliasName,
		Became:    sqlc.GoTimeToPBTimestamp(row.Became),
		Remark:    row.Remark.String,
		// brand
		BrandName:                 row.BrandName,
		BrandPic:                  row.BrandPic.String,
		BrandFansCount:            row.FansCount,
		BrandPublishActivityCount: row.PublishActivityCount,
	}
}

func mapBrandSpokesmanWithBrandEntityToPb(list []sqlc.ListNormalBrandSpokesmanWithBrandsByUserIDRow, f func(sqlc.ListNormalBrandSpokesmanWithBrandsByUserIDRow) *brandSpokesmanGrpc.BrandSpokesmanWithBrandEntity) []*brandSpokesmanGrpc.BrandSpokesmanWithBrandEntity {
	r := make([]*brandSpokesmanGrpc.BrandSpokesmanWithBrandEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformBrandSpokesmanWithUserEntityToPb(row sqlc.ListNormalBrandSpokesmanWithUsersByBrandIDRow) *brandSpokesmanGrpc.BrandSpokesmanWithUserEntity {
	return &brandSpokesmanGrpc.BrandSpokesmanWithUserEntity{
		// brand_admin
		Id:                   row.ID,
		UserId:               row.UserID,
		BrandId:              row.BrandID,
		AliasName:            row.AliasName,
		Became:               sqlc.GoTimeToPBTimestamp(row.Became),
		Remark:               row.Remark.String,
		EndorseActivityCount: row.EndorseActivityCount,
		SaleAmount:           row.SaleAmountCalculated, // 目前使用实时计算的
		// user
		SpokesmanUserNickName: row.SpokesmanUserNickName,
		SpokesmanUserPic:      row.SpokesmanUserPic,
		// stat
		FansCount: row.FansCount,
	}
}

func mapBrandSpokesmanWithUserEntityToPb(list []sqlc.ListNormalBrandSpokesmanWithUsersByBrandIDRow, f func(sqlc.ListNormalBrandSpokesmanWithUsersByBrandIDRow) *brandSpokesmanGrpc.BrandSpokesmanWithUserEntity) []*brandSpokesmanGrpc.BrandSpokesmanWithUserEntity {
	r := make([]*brandSpokesmanGrpc.BrandSpokesmanWithUserEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                            brand_spokesmanJoins entity of query                      */
/****************************************************************************************/

// ListNormalBrandSpokesmanWithBrandsByUserID  获取代言人的代言品牌列表
func (s *BrandAPIService) ListNormalBrandSpokesmanWithBrandsByUserID(ctx context.Context, req *brandSpokesmanGrpc.ListNormalBrandSpokesmanWithBrandsByUserIDRequest) (res *brandSpokesmanGrpc.ListNormalBrandSpokesmanWithBrandsByUserIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_spokesmanImp->ListNormalBrandSpokesmanWithBrandsByUserID:%v", req)
	res = &brandSpokesmanGrpc.ListNormalBrandSpokesmanWithBrandsByUserIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	q := s.dao.Q
	total, err := q.CountNormalBrandSpokesmansByUserID(ctx, req.UserId)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}
	brandSpokesmanWithBrands, err := q.ListNormalBrandSpokesmanWithBrandsByUserID(ctx, sqlc.ListNormalBrandSpokesmanWithBrandsByUserIDParams{
		Limit:  req.Limit,
		Offset: req.Offset,
		UserID: req.UserId,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.BrandSpokesmanWithBrands = mapBrandSpokesmanWithBrandEntityToPb(brandSpokesmanWithBrands, transformBrandSpokesmanWithBrandEntityToPb)
	return
}

// ListNormalBrandSpokesmanWithUsersByBrandID  获取代言人及其用户信息列表
func (s *BrandAPIService) ListNormalBrandSpokesmanWithUsersByBrandID(ctx context.Context, req *brandSpokesmanGrpc.ListNormalBrandSpokesmanWithUsersByBrandIDRequest) (res *brandSpokesmanGrpc.ListNormalBrandSpokesmanWithUsersByBrandIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_spokesmanImp->ListNormalBrandSpokesmanWithUsersByBrandID:%v", req)

	res = &brandSpokesmanGrpc.ListNormalBrandSpokesmanWithUsersByBrandIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	brandID := req.BrandId
	keyword := req.Keyword
	isKeywordEmpty := keyword == ""
	keywordLike := fmt.Sprintf("%%%s%%", keyword)

	total, err := q.CountNormalBrandSpokesmanWithUsersByBrandID(ctx, sqlc.CountNormalBrandSpokesmanWithUsersByBrandIDParams{
		Created:        ts,
		BrandID:        brandID,
		IsKeywordEmpty: isKeywordEmpty,
		Keyword:        keywordLike,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	brandSpokesmanWithUsers, err := q.ListNormalBrandSpokesmanWithUsersByBrandID(ctx, sqlc.ListNormalBrandSpokesmanWithUsersByBrandIDParams{
		Limit:          req.Limit,
		Offset:         req.Offset,
		Created:        ts,
		BrandID:        brandID,
		IsKeywordEmpty: isKeywordEmpty,
		Keyword:        keywordLike,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.BrandSpokesmanWithUsers = mapBrandSpokesmanWithUserEntityToPb(brandSpokesmanWithUsers, transformBrandSpokesmanWithUserEntityToPb)
	return
}
